import binascii
import functools
import json
import time

import redis
from redis.client import Redis
from rediscluster import RedisCluster

mconn = Redis(host="192.168.35.110", port=6379, db=0, decode_responses=True)
sconn1 = Redis(host="192.168.35.110", port=6380, db=0, decode_responses=True)
redis_basis_conn = [{'host': '192.168.35.110', 'port': 6379}, {'host': '192.168.35.110', 'port': 6380},
                    {'host': '192.168.35.110', 'port': 6381}]

res = RedisCluster(startup_nodes=redis_basis_conn)

CONFIG = {}
CHECKED = {}
REDIS_CONNECTIONS = {}


def get_config(conn, type, component, wait=1):
    key = 'config:%s:%s' % (type, component)
    if CHECKED.get(key) is None or CHECKED.get(key) < time.time() - wait:
        CHECKED[key] = time.time()
        config = json.loads(conn.get(key) or '{}')
        config = dict((str(k), config[k]) for k in config)
        old_config = CONFIG.get(key)
        if config != old_config:
            CONFIG[key] = config
    return CONFIG.get(key)


def get_redis_config(component, wait=1):
    key = 'config:redis:' + component
    old_config = CONFIG.get(key, object())
    config = get_config(mconn, 'redis', component, wait)
    if config != old_config:
        REDIS_CONNECTIONS[key] = redis.Redis(**config)
    return REDIS_CONNECTIONS.get(key)


def shard_key(base, key, total_element, shard_size):
    if isinstance(key, (int)) or key.isdigit():
        shard_id = int(str(key), 10) // shard_size
    else:
        shards = 2 * total_element // shard_size
        shard_id = binascii.crc32(key.encode()) % shards
    return "%s%s" % (base, shard_id)


def get_shard_connection(commponent, key, shard_count, wait=1):
    shard = shard_key(commponent, 'x' + str(key), shard_count, 2)
    return get_redis_config(shard, wait)


def sharded_connection(commponent, shard_count, wait=1):
    def wrapper(function):
        @functools.wraps(function)
        def call(key, *args, **kwargs):
            conn = get_shard_connection(commponent, key, shard_count, wait)
            return function(conn, key, *args, **kwargs)

        return call

    return wrapper


def print_hi(name):
    print(f'Hi, {name}')  # 按 Ctrl+F8 切换断点。


# 按间距中的绿色按钮以运行脚本。
if __name__ == '__main__':
    # key1 = 'config:redis:slave-1'
    # config1 = {'host': '192.168.35.110', 'port': 6380, 'db': 0, 'decode_responses': True}
    # key2 = 'config:redis:slave-2'
    # config2 = {'host': '192.168.35.110', 'port': 6381, 'db': 0, 'decode_responses': True}
    # mconn.set(key1, json.dumps(config1))
    # mconn.set(key2, json.dumps(config2))
    # key2 = 'config:redis:logs0'
    # config2 = {'host': '192.168.35.110', 'port': 6380, 'db': 0, 'decode_responses': True}
    # mconn.set(key1, json.dumps(config1))
    # mconn.set(key2, json.dumps(config2))
    # config = get_redis_config('slave-1', 1)
    # config2 = get_shard_connection('logs', 7, 2, 1)
    # print_hi('PyCharm')
    # mconn.set('name', 'hyman')
    # sconn1.set('age', '18')
    # sconn1.set('name', 'tom')
    # mconn.set('age', '17')
    res.set('name', 'hyman')
